package com.googlecode.yoohoo.xmppcore.protocol.stanza;

import java.util.ArrayList;
import java.util.List;

import com.googlecode.yoohoo.xmppcore.protocol.JabberId;
import com.googlecode.yoohoo.xmppcore.protocol.translation.ITranslator;
import com.googlecode.yoohoo.xmppcore.protocol.translation.IXmlWriter;
import com.googlecode.yoohoo.xmppcore.protocol.translation.XmlWriter;

public abstract class Stanza implements ITranslator {
	public static final String ATTRIBUTE_NAME_FROM = "from";
	public static final String ATTRIBUTE_NAME_TO = "to";
	public static final String ATTRIBUTE_NAME_ID = "id";
	public static final String ATTRIBUTE_NAME_TYPE = "type";
	public static final String ATTRIBUTE_PREFIX_XML_LANG = "xml";
	public static final String ATTRIBUTE_LOCALNAME_XML_LANG = "lang";
	
	protected JabberId from;
	protected JabberId to;
	protected String id;
	protected String type;
	protected String xmlLang;
	protected List<Object> objects;
	
	public Stanza() {
	}
	
	public JabberId getFrom() {
		return from;
	}

	public String getId() {
		return id;
	}

	public JabberId getTo() {
		return to;
	}

	public String getType() {
		return type;
	}

	public String getXmlLang() {
		return xmlLang;
	}

	public void setFrom(JabberId from) {
		this.from = from;
	}

	public void setId(String id) {
		this.id = id;
	}

	public void setTo(JabberId to) {
		this.to = to;
	}

	public void setXmlLang(String xmlLang) {
		this.xmlLang = xmlLang;
	}
	
	public void setType(String type) {
		if (!checkType(type)) {
			throw new IllegalArgumentException();
		}
		
		this.type = type;
	}
	
	protected boolean checkType(String type) {
		if (type == null)
			return false;
		
		if ("error".equals(type))
			return true;
		
		for (String validType : getValidTypes()) {
			if (type.equals(validType))
				return true;
		}
		
		return false;
	}
	
	protected abstract String[] getValidTypes();

	public void setObjects(List<Object> objects) {
		this.objects = objects;
	}
	
	public List<Object> getObjects() {
		if (objects == null) {
			objects = new ArrayList<Object>(0);
		}
		return objects;
	}
	
	public void setObject(Object object) {
		if (objects != null) {
			objects.clear();
		} else {
			objects = new ArrayList<Object>(1);
		}
		
		objects.add(object);
	}
	
	public Object getObject() {
		if (objects == null || objects.size() == 0)
			return null;
		
		return objects.get(0);
	}
	
	@Override
	public String toXml() {
		IXmlWriter writer = new XmlWriter();
		if (getStanzaKind() == null) {
			throw new IllegalStateException("Stanza kind hasn't be set.");
		}
		writer.writeStartElement(getStanzaKind().toString());
		
		if (type != null) {
			writer.writeAttribute("type", type);
		}
		
		if (id != null) {
			writer.writeAttribute("id", id);
		}
		
		if (from != null) {
			writer.writeAttribute("from", from.toString());
		}
		
		if (to != null) {
			writer.writeAttribute("to", to.toString());
		}
		
		if (xmlLang != null) {
			writer.writeAttribute("xml:lang", xmlLang);
		}
		
		doToXml(writer);
		
		if (objects != null) {
			for (Object object : objects) {
				if (object != null && object instanceof ITranslator) {
					ITranslator translator = (ITranslator)object;
					writer.writeCharacters(translator.toXml(), false);
				}
			}
		}
		writer.writeEndElement();

		return writer.toXml();
	}
	
	protected void doToXml(IXmlWriter writer) {
		// do nothing
	}
	public abstract StanzaKind getStanzaKind();
}
